<script setup lang="ts">
import { CheckCircleFilled, CloseCircleOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { computed, reactive, ref } from 'vue';
import { useRequest } from 'vue-request';

/**
 * APIs
 */
import { code, register } from '@/request/auth';

/**
 * Resources
 */
import LoginLogo from '@/assets/login-logo.svg';

/**
 * Types
 */
import type { FormInstance } from 'ant-design-vue';
import type { RuleObject } from 'ant-design-vue/es/form';
import type { RegisterData } from '@/request/auth';

/**
 * States
 */
const state = reactive({
    error: {
        err1: true,
        err2: true,
        err3: true,
    },
    form: {
        phone: '',
        code: '',
        password: '',
        confirmPassword: '',
        agreement: [],
    },
    open: false,
    time: 0,
});

const formRef = ref<FormInstance>();

/**
 * Requests
 */
// 验证码
const { loading: loadingCode, run: runCode } = useRequest(code, {
    manual: true,
    onSuccess: ({ data }) => {
        if (data.code !== 200) {
            message.error(data.message);
            return;
        }

        state.time = 120;

        const timer = setInterval(() => {
            state.time -= 1;

            if (state.time <= 0) {
                clearInterval(timer);
                state.time = 0;
            }
        }, 1000);
    },
});

// 注册
const { loading: loadingRegister, run: runRegister } = useRequest(register, {
    manual: true,
    onSuccess: ({ data }) => {
        if (data.code !== 200) {
            message.error(data.message);
            return;
        }

        window.location.href = `${import.meta.env.VITE_REDIRECT_URL}/?t=${data.result.token}`;
    },
});

/**
 * Events
 */
// 当验证码点击
const onCodeClick = () => {
    formRef.value?.validate('phone').then((value) => {
        runCode({
            phone: value.phone,
            codeType: 0,
        });
    });
};

// 当密码修改
const onPasswordChange = () => {
    state.error.err1 = false;
    state.error.err2 = false;
    state.error.err3 = false;

    const value = state.form.password;

    if (value.length < 6 || value.length > 20 || state.form.phone === value) {
        state.error.err1 = true;
    }

    if (!/^[a-zA-Z0-9!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]+$/.test(value)) {
        state.error.err2 = true;
    }

    // 字母 Letter
    const hasL = /[a-zA-Z]+/.test(value);
    // 数字 Number
    const hasN = /\d+/.test(value);
    // 标点符号 Punctuation
    const hasP = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]+/.test(value);

    if ((!hasL && !hasN) || (!hasL && !hasP) || (!hasN && !hasP)) {
        state.error.err3 = true;
    }
};

// 当密码聚焦
const onPasswordFocus = () => {
    formRef.value?.clearValidate('password');

    setTimeout(() => {
        state.open = true;
    }, 100);
};

// 当表单完成
const onFormFinish = (value: RegisterData) => {
    runRegister(value);
};

/**
 * ChildrenProps
 */
const formRules = computed<Record<string, RuleObject | RuleObject[]>>(() => ({
    phone: {
        validator: (_, value) => {
            if (!/^1\d{10}$/.test(value)) {
                return Promise.reject('请输入手机号');
            }

            return Promise.resolve();
        },
    },
    code: {
        message: '请输入验证码',
        required: true,
    },
    password: {
        trigger: 'blur',
        validator: (_, value) => {
            if (value.trim() === '') {
                return Promise.reject('请输入密码');
            }

            if (!/^[a-zA-Z0-9!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]+$/.test(value)) {
                return Promise.reject('密码设置不符合要求');
            }

            // 字母 Letter
            const hasL = /[a-zA-Z]+/.test(value);
            // 数字 Number
            const hasN = /\d+/.test(value);
            // 标点符号 Punctuation
            const hasP = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]+/.test(value);

            if ((!hasL && !hasN) || (!hasL && !hasP) || (!hasN && !hasP)) {
                return Promise.reject('密码设置不符合要求');
            }

            if (state.form.confirmPassword !== '') {
                formRef.value?.validate('confirmPassword');
            }

            return Promise.resolve();
        },
    },
    confirmPassword: {
        validator: (_, value) => {
            if (value.trim() === '') {
                return Promise.reject('请输入密码');
            }

            if (state.form.password !== state.form.confirmPassword) {
                return Promise.reject('两次输入的密码不一致，请重新输入');
            }

            return Promise.resolve();
        },
    },
    agreement: {
        message: '请先勾选',
        required: true,
        trigger: 'change',
        type: 'array',
    },
}));
</script>

<template>
    <div class="login-page">
        <!-- Logo -->
        <a-space align="center" class="logo" :size="6">
            <img alt="" :src="LoginLogo" />

            <div>冒泡开发者平台</div>
        </a-space>

        <!-- Form -->
        <a-config-provider
            :theme="{
                components: {
                    Form: {
                        motionDurationSlow: '0s',
                    },
                },
            }"
        >
            <a-form
                autocomplete="off"
                class="form"
                :model="state.form"
                ref="formRef"
                :rules="formRules"
                @finish="onFormFinish"
            >
                <a-row align="bottom" class="title" justify="space-between">
                    <a-col>
                        <a-typography-title :level="3" style="margin: 0">
                            注册账号
                        </a-typography-title>
                    </a-col>

                    <a-col>已有账号？<RouterLink to="/login">登录</RouterLink></a-col>
                </a-row>

                <!-- 账号 -->
                <a-form-item name="phone">
                    <a-input-group compact>
                        <a-form-item-rest>
                            <a-select size="large" style="width: 80px" value="+86">
                                <a-select-option value="+86">+86</a-select-option>
                            </a-select>
                        </a-form-item-rest>

                        <a-input
                            v-model:value="state.form.phone"
                            :maxlength="11"
                            placeholder="请输入手机号"
                            size="large"
                            style="width: calc(100% - 80px)"
                        />
                    </a-input-group>
                </a-form-item>

                <!-- 验证码 -->
                <a-form-item name="code">
                    <a-input-group compact>
                        <a-input
                            v-model:value="state.form.code"
                            :maxlength="4"
                            placeholder="请输入验证码"
                            size="large"
                            style="width: calc(100% - 120px)"
                        />

                        <a-button
                            class="code-button"
                            :disabled="state.time > 0"
                            :loading="loadingCode"
                            size="large"
                            style="width: 120px"
                            @click="onCodeClick"
                        >
                            {{ state.time > 0 ? state.time : '获取验证码' }}
                        </a-button>
                    </a-input-group>
                </a-form-item>

                <!-- 密码 -->
                <a-dropdown arrow :open="state.open" placement="bottomLeft" trigger="click">
                    <a-form-item name="password">
                        <a-input-password
                            v-model:value="state.form.password"
                            autocomplete="new-password"
                            :maxlength="20"
                            placeholder="请输入密码"
                            size="large"
                            @blur="state.open = false"
                            @change="onPasswordChange"
                            @focus="onPasswordFocus"
                        />
                    </a-form-item>

                    <template #overlay>
                        <div class="rule-list">
                            <p>
                                <CloseCircleOutlined
                                    v-if="state.error.err1"
                                    style="color: #e52121"
                                />

                                <CheckCircleFilled v-else style="color: #24c576" />

                                6-20 个字符，密码不能是相同的用户名
                            </p>

                            <p>
                                <CloseCircleOutlined
                                    v-if="state.error.err2"
                                    style="color: #e52121"
                                />

                                <CheckCircleFilled v-else style="color: #24c576" />

                                只能包含字母、数字以及标点符号（除空格）
                            </p>

                            <p>
                                <CloseCircleOutlined
                                    v-if="state.error.err3"
                                    style="color: #e52121"
                                />

                                <CheckCircleFilled v-else style="color: #24c576" />

                                字母、数字和标点符号至少包含 2 种
                            </p>
                        </div>
                    </template>
                </a-dropdown>

                <!-- 确认密码 -->
                <a-form-item name="confirmPassword">
                    <a-input-password
                        v-model:value="state.form.confirmPassword"
                        autocomplete="new-password"
                        :maxlength="20"
                        placeholder="确认密码"
                        size="large"
                    />
                </a-form-item>

                <!-- 协议 -->
                <a-form-item name="agreement">
                    <a-checkbox-group v-model:value="state.form.agreement">
                        <a-checkbox name="agreement" style="font-size: 12px" value="1">
                            已阅读并同意物栖账号
                            <a
                                href="https://app.jeejio.com/agreements/user.html"
                                ref="noopener"
                                target="_blank"
                            >
                                物栖 OS 生态产品合作协议
                            </a>
                            、
                            <a
                                href="https://app.jeejio.com/agreements/privacy.html"
                                ref="noopener"
                                target="_blank"
                            >
                                隐私协议
                            </a>
                        </a-checkbox>
                    </a-checkbox-group>
                </a-form-item>

                <!-- Submit -->
                <a-form-item>
                    <a-button
                        :block="true"
                        html-type="submit"
                        :loading="loadingRegister"
                        size="large"
                        type="primary"
                    >
                        注册
                    </a-button>
                </a-form-item>
            </a-form>
        </a-config-provider>
    </div>
</template>

<style scoped lang="less">
.login-page {
    height: 100vh;
    background: #f7f8fc url('@/assets/login-back.png') top center / 100% 50% no-repeat;

    .logo {
        margin: 32px;
        color: #fff;
        font-size: 20px;
        font-weight: 500;
    }

    .form {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 480px;
        padding: 30px 40px;
        background-color: #fff;
        border-radius: 2px;
        transform: translate(-50%, -50%);

        .title {
            margin-bottom: 24px;
        }

        .code-button {
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
        }
    }
}

.rule-list {
    padding: 12px;
    background-color: #fff;
    border-radius: 4px;
    box-shadow:
        0 6px 16px 0 rgba(0, 0, 0, 0.08),
        0 3px 6px -4px rgba(0, 0, 0, 0.12),
        0 9px 28px 8px rgba(0, 0, 0, 0.05);

    p {
        margin-bottom: 10px;
        font-size: 14px;
        line-height: 14px;

        &:last-child {
            margin-bottom: 0;
        }
    }
}
</style>
